

/**
 * Represents a polygon; building block of a 3D surface
 * @author Narendra J. Mondal
 * @date 15.01.2012
 */

package plotter;

import java.awt.*;

class Polygon3D
{
	/**
	 * the vertices of polygon
	 */
	private int[] xp = new int[4];
	private int[] yp = new int[4];
	
	/**
	 * the z-coordinate of centre of gravity; used to calculate back face & illumination
	 */
	public double cgz;
	
	/**
	 * whether the polygon is obscured by other polygon
	 */
	private boolean renderable = true;
	
	/**
	 * is it a back face?
	 */
	private boolean bkface = false;
	
	public Polygon3D(Point3D p1, Point3D p2, Point3D p3, Point3D p4, int w, int h) 
	{
		xp[0] = (int)p1.x; 
		yp[0] = (int)p1.y;
		
		xp[1] = (int)p2.x; 
		yp[1] = (int)p2.y;
		
		xp[2] = (int)p3.x; 
		yp[2] = (int)p3.y;
		
		xp[3] = (int)p4.x; 
		yp[3] = (int)p4.y;
		
		
		if (p1.z > 0 || p2.z > 0 || p3.z > 0 || p4.z > 0) 
			renderable = false;
		
		/*
		 * now we calculate the view plane normal
		 * if A,B,C be three points on a plane, then AB x AC is normal to the plane
		 */
		double[] v1 = { p2.x - p1.x, p2.y - p1.y, p2.z - p1.z };
		double[] v2 = { p3.x - p1.x, p3.y - p1.y, p3.z - p1.z };
		
		// we only need the z-coordinate of the normal(cross prod. of v1,v2)
		
		double n2 = v1[0] * v2[1] - v1[1] * v2[0];
		
		// polygon is back-faced if and only if the distance of normal is -ve  
		if (n2 <= 0) bkface = true;
		
		cgz = (p1.z + p2.z + p3.z + p4.z) / 4.0;
		
	}
	/**
	 * Linearly blend two colours
	 * @param c1 first colour
	 * @param c2 second colour
	 * @param amt amount of blending
	 * @return blended colour
	 */
	public Color blendColors(Color c1, Color c2, double amt) 
	{
		double r = amt * c1.getRed() + (1 - amt) * c2.getRed();
		double g = amt * c1.getGreen() + (1 - amt) * c2.getGreen();
		double b = amt * c1.getBlue() + (1 - amt) * c2.getBlue();
		return new Color((int)r,(int)g,(int)b);
	}
	/**
	 * Draw the polygon on screen
	 * @param g Grpahics2D
	 * @param s1 first surface colour
	 * @param s2 second surface colour
	 * @param amt amount of blend
	 * @param gc grid colour
	 * @param fill is the polygon to be filled?
	 */
	public void render(Graphics2D g, Color s1, Color s2, double amt, Color gc, boolean fill) {
		
		if (!renderable) return;
		
		
		if (fill) {
			Color dc = bkface ? s2.darker() : s1.darker();
			g.setColor(bkface ? blendColors(s2, dc, amt) : blendColors(s1, dc, amt));
			g.fillPolygon(xp, yp, 4);
		}
		
		g.setColor(gc);
		g.drawPolygon(xp, yp, 4);
	}
}

/**
 * Comparator for two polygons according to their z-component of depth
 * @author Narendra J. Mondal
 *
 */
class PolyComparator implements java.util.Comparator<Polygon3D>
{
	public int compare(Polygon3D p1, Polygon3D p2) {
		if (p1.cgz > p2.cgz) return -1;
		else if (p1.cgz == p2.cgz) return 0;
		else return 1;
	}
}
